package com.ruoyi.common.utils;

import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * @author
 * @description AES加解密（ECB和CBC模式）
 * @date 2023/12/8 15:08
 */
public class AESEncryptUtil {

    /**
     * 加密模式
     * ECB: AES/ECB/PKCS5Padding
     * CBC: AES/CBC/NoPadding
     */
    private static final String[] TRANSFORM_ALGORITHM = new String[]{"AES/ECB/PKCS5Padding", "AES/CBC/NoPadding"};
    /**
     * 初始向量样式 IV
     */
    private static String iv =  "HBJNRU56MDk4NzK6";
    private static final String ALGORITHM = "AES";
    private static final String CHARSET_NAME = "UTF-8";
    /**
     * AES加解key样式
     */
    public static String ENCRYPT_KEY = "7CC408B24462ABD1";

    /**
     * AES的ECB模式加解
     * @param data 待加密参数
     * @param key 加密key
     * @return
     */
    public static String encryptECB(String data, String key) {
        if (StringUtils.isEmpty(key)) {
            throw new IllegalArgumentException("加密失败,加密key为空");
        }
        SecretKeySpec aesKey = new SecretKeySpec(key.getBytes(Charset.forName(CHARSET_NAME)), ALGORITHM);
        try {
            Cipher cipher = Cipher.getInstance(TRANSFORM_ALGORITHM[0]);
            cipher.init(Cipher.ENCRYPT_MODE, aesKey);
            byte[] encrypted = cipher.doFinal(data.getBytes(Charset.forName(CHARSET_NAME)));
            // 使用Base64来包装是规避报错Input length must be multiple of 16 when decrypting with padded cipher
            // 解密的字节数组必须是16的倍数
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new IllegalArgumentException("加密失败: "+ e.getMessage());
        }
    }

    /**
     * AES的ECB模式解密
     * @param data 待解密参数
     * @param key 解密key
     * @return
     */
    public static String decryptECB(String data, String key) {
        if (StringUtils.isEmpty(key)) {
            throw new IllegalArgumentException("解密失败，解密key为空");
        }
        byte[] decode = Base64.getDecoder().decode(data.getBytes(StandardCharsets.UTF_8));
        SecretKeySpec aesKey = new SecretKeySpec(key.getBytes(Charset.forName(CHARSET_NAME)), ALGORITHM);
        try {
            Cipher cipher = Cipher.getInstance(TRANSFORM_ALGORITHM[0]);
            cipher.init(Cipher.DECRYPT_MODE, aesKey);
            return new String(cipher.doFinal(decode));
        } catch (Exception e) {
            throw new IllegalArgumentException("解密失败: "+ e.getMessage());
        }
    }

    /**
     * AES的CBC模式加密
     * @param data 要加密的数据
     * @param key 加密key
     * @return 加密的结果
     */
    public static String encryptCBC(String data, String key) {
        try {
            // "算法/模式/补码方式"
            Cipher cipher = Cipher.getInstance(TRANSFORM_ALGORITHM[1]);
            int blockSize = cipher.getBlockSize();
            byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
            int plaintextLength = dataBytes.length;
            if (plaintextLength % blockSize != 0) {
                plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
            }
            byte[] plaintext = new byte[plaintextLength];
            System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
            SecretKeySpec keyStr = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
            IvParameterSpec ivStr = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.ENCRYPT_MODE, keyStr, ivStr);
            byte[] encrypted = cipher.doFinal(plaintext);
            return Base64.getEncoder().encodeToString(encrypted);
        } catch (Exception e) {
            throw new IllegalArgumentException("加密失败: "+ e.getMessage());
        }
    }

    /**
     * AES的CBC模式解密
     * @param data 要解密的数据
     * @param key 解密key
     * @return 解密的结果
     */
    public static String decryptCBC(String data, String key) {
        try {
            byte[] encrypted1 = Base64.getDecoder().decode(data);
            Cipher cipher = Cipher.getInstance(TRANSFORM_ALGORITHM[1]);
            SecretKeySpec keyStr = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "AES");
            IvParameterSpec ivStr = new IvParameterSpec(iv.getBytes(StandardCharsets.UTF_8));
            cipher.init(Cipher.DECRYPT_MODE, keyStr, ivStr);
            byte[] original = cipher.doFinal(encrypted1);
            return new String(original, StandardCharsets.UTF_8);
        } catch (Exception e) {
            throw new IllegalArgumentException("解密失败: "+ e.getMessage());
        }
    }

    /**
     * AES/ECB 加密
     * @param content   待加密明文
     * @param secretKey 密钥（必须为16/24/32字节）
     * @return Base64 编码的密文
     */
    public static String encrypt(String content, String secretKey) throws Exception {
        // 1. 校验密钥长度
        if (secretKey.length() != 16 && secretKey.length() != 24 && secretKey.length() != 32) {
            throw new IllegalArgumentException("密钥长度需为16/24/32字节");
        }

        // 2. 初始化加密组件
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES");
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);

        // 3. 执行加密并Base64编码
        byte[] encryptedBytes = cipher.doFinal(content.getBytes("UTF-8"));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    /**
     * AES/ECB 解密
     * @param encryptedContent Base64 编码的密文
     * @param secretKey        密钥
     * @return 解密后的明文
     */
    public static String decrypt(String encryptedContent, String secretKey) throws Exception {
        // 1. 解码Base64并初始化解密组件
        byte[] encryptedBytes = Base64.getDecoder().decode(encryptedContent);
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes("UTF-8"), "AES");
        cipher.init(Cipher.DECRYPT_MODE, keySpec);

        // 2. 执行解密
        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
        return new String(decryptedBytes, "UTF-8");
    }

    public static void main(String[] args) throws Exception {
        String data = "123456";
        String keyStr = "7CC408B24462ABD1";
        String encryDataStr = encryptECB(data, keyStr);
        System.out.println("encryptECB = " + encryDataStr);
        System.out.println("decryptECB = " + decryptECB(encryDataStr, keyStr));
        System.out.println("decryptECB = " + decryptECB(encryDataStr, keyStr).length());
        encryDataStr = encryptCBC(data, keyStr);
        System.out.println("encryptCBC = " + encryDataStr);
        System.out.println("decryptCBC = " + decryptCBC(encryDataStr, keyStr).replace(" ",""));
        System.out.println("decryptCBC = " + decryptCBC(encryDataStr, keyStr).length());
        encryDataStr = encrypt(data, keyStr);
        System.out.println("encrypt = " + encryDataStr);
        System.out.println("decrypt = " + decrypt(encryDataStr, keyStr));
        System.out.println(decrypt("l6zGczls2MQKNy4FddLSFg==","7CC408B24462ABD1"));
    }

}

